package main.test.SparkAPI.Baics.valuevars

object testValueVars {


  //Values

  /**
   * Assignments improve your code's readability by breaking down the computation
   * and assigning meaningful names to it. They can also increase your
   * program's performance by saving intermediate results that you can reuse
   * and share between process.Values are the most commonly used type of assignments in scala.
   *
   * In the next example, you'll see how values can improve your code's readability,
   * particularly when dealing with complex scenarios. Suppose you are performing some
   * calculation  to mark exams with the following requirements: each exam has three
   * questions, each with a possible score of 3 point, and its final mark must
   * be between 1 and 10. Several solutions are possible; let's pick one of them.
   * You could caculate the average score for all the questions and then convert it to a number from
   * 1 to 10. For example, you should follow these steps for three questions scoring 1.5 , 2 and 2.5:
   * 1 you compute the average score for all the questions:(1.5+2+2.5)/3 is 2
   * 2 you scale the average score from 1 to 10. Considering that the maximum score
   * possible for each question is 3, then you can rescale it as follows:2*10/3 is about
   * 6.6.
   * 3 you round 6.6 up to the closest integer and obtain 7.
   */
    def markExam(q1:Double, q2: Double, q3: Double) =
      Math.round((
        (q1 + q2 + q3)/3
        )*10/3)

  /**
   *
   * markExam replicate the calculations described, but it is difficult ot
   * identify
   * its objective and computation steps.
   * You cna improve the readability of the markExam
   * function by using values with descriptive names.
   */
    def markExam2(q1:Double, q2: Double, q3:Double ) = {
      val avgScore = (q1 + q2 + q3) / 3
      val scaledScore = avgScore * 10 / 3
      Math.round(scaledScore) // No need for the return keyword; the
      // last expression is the one returned
    }

  /**
   * Values are a fundamental component of yor code. In scala,
   * you declare them by using the keyword val.You can only initialize them once because they are
   * immutable; if you try to reaasign them, the code will not compile.
   * Consider the following exapmle:
   *{{{
   *   val a = 1
   *   val a: Int = 1
   *   a = 2
   *   error:reassignment to val
   *   // you cannot reassign a value, which is an immutable assignment.
   *}}}
   */

  /**
   * When declaring a value, its type is optional; the compiler tries
   * to infer it for you. If the compiler infers an unexpected tye, you
   * can provide it explicitly; the compiler will check if the type you
   * specified is compatible with the assignment of your value and eventually return
   * a compilation error:
   * val b:Int = 1
   * val c:Double = 1// compiler knows how to fit an Int int a Double
   * val d:Int = "not-an-int"
   * error type mismatch;
   * found: String("not-an-int")
   * required:Int // cannot assign a String to an Int
   * val d:Any = "not-an-int"
   * Any is the root of the class hierarchy: you can assign any value to it.
   *
   *
   */
    //Syntax diagram on values in scala
    // val name: type = expression

    //variables

  /**
   * In previous section, you wrote a function to mark an exam. Let's
   * expand it so that you cna compute the average score of all exams you marked so far.
   * Values are immutabl, so you cannot use them to keep track of how your stats evolve,
   * which is the mutable state of your program.In these cases, you can use variable.
   *
   *{{{
   *   var marksSum = 0
   *   var marksCount = 0
   *   def averageMark:Double =
   *    marksSum.toDouble/marksCount
   *    // When converting marksSum to Double,
   *    the result of your division must be a Double.
   *    An integer divided by another integer produces an  Int
   *    while diving a double by integer returns a double.
   *}}}
   */
    var marksSum = 0
    var marksCount = 0
    def markExam3(q1:Double, q2:Double, q3:Double):Int = {
      val avgScore = (q1 + q2 + q3) / 3
      val scaledScore = avgScore * 10 / 3
      val mark = Math.round(scaledScore).toInt

      marksSum += mark
      marksCount += 1
      mark
    }
  def averageMark:Double =
    marksSum.toDouble/marksCount

  /**
   * variables are very similar to values: while you can assign values only
   * once, you can reassign variables multiple times.
   * you donot need to provide a type for your variable; the compiler will infer ti for you
   * When doing so, the compiler makes sure that the assignment is compatible with it.
   * var name : Type = expression.
   */

  /**
   * Think in scala: val or var?
   * When in doubt, you should always try to use val instead var.
   * Having immutable values makes your
   * programs safe from concurrency inconsistency in exchange for some
   * additional memory allocation; most of the time,
   * you will not notice this extra memory usage thanks to the JVM's garbage collection.
   * Using  mutable structure makes you programs challenging to test and reason about;
   * you need to pay attention to how processes share data and how the evolve,
   * mutable structures may be more performant but they also expose yor
   * code to complex concurrency issues such as data inconcurrency, dead blocks,
   * and resource starvation.
   * Before choosing to stick with a var , you should make sure you
   * have tried everything else in your book of tricks;
   * variable should be your last and least desirable option.
   * At this point in your scala journey, you may think that using mutability is
   * often than only option.But this is not the case: in future units and lessons, you'll
   * discover many tools and techniques, such as case classes, that will
   * allow you to get rid of var from your code.
   */


  def main(args: Array[String]): Unit = {
    /**
     * Write code that use values to save and reuse computational results
     * Implement programs that carefully take advantage of variables
     * Scala has a clear separation between mutable and immutable assignments.
     * TODO: values are immutable: you cannot modify them after creating them.
     * TODO: Variables are mutable: they can refer to different instances over time.
     * Deciding when to declare a value rather
     * than a variable is essential for your code to be fast and bug0free.
     * Variables are more straightforward to use in your code
     * because you can modify them.
     * However, they can make your program extremely difficult to
     * maintain and lead to errors when different processes try to
     * do so simultaneously.
     * Values can be challenging to use because you can not modify them once created.
     * But they can make your program easier to understand:
     * their assignments never change, so you cna easily predict and test
     * their evaluation.
     * They also guarantee that your code will not be affected by concurrency issues, such
     * as data inconsistencies, resources starvation, and dead blocks, when
     * accessed by several threads.
     * A fragment of code that multiple processes can access without causing concurrency
     * issues is thread-safe. In the capstone for this unit, you'll define both
     * values and variables to name fragments of code and make your program more readable.
     *
     */
    /**
     * Consider the other languages you have encountered so frar
     * in your career.
     * Do they make a clear distinction between mutable and immutable assignments? if
     * so ,how ? if not, can you think of advantages and disadvantages
     * of not having a clear separation between the two?
     */

  }

}
